/*
 *  Project:            TSNSwitch_RVPE.
 *  Module name:        RV_PE_Top.
 *  Description:        Top Module of RV_PE_Top.
 *  Last updated date:  2023.03.14.
 *
 *  Communication with Junnan Li <lijunnan@nudt.edu.cn>.
 *  Copyright and related rights are licensed under the MIT license.
 *
 *  Noted:
 *    1) exchange information between TSN and CAN;
 *
 */

`timescale 1ns / 1ps

// `define TEST_LOOPBACK
// `define SUPPORT_MULTIPULE_PORT

module RV_PE_Top(
  //* clock and reset;
   input wire           rst_n
  ,input wire           clk_50m
  ,input wire           clk_125m

  //* uart rx/tx from/to host;
  ,input                uart_rx    //* fpga receive data from host;
  ,output  wire         uart_tx    //* fpga send data to host;
  ,input                uart_cts
  ,output  wire         uart_rts

  // //* sgmii port
  // ,input  wire          SFP_REFCLK_P   
  // ,input  wire          SFP_REFCLK_N 
  // ,output wire          FX_RX_P
  // ,output wire          FX_RX_N
  // ,input  wire          FX_TX_P
  // ,input  wire          FX_TX_N

  //* gmii port
  ,input  wire          gmii_rx_clk 
  ,input  wire  [7:0]   gmiiRxd     
  ,input  wire          gmiiEn      
  ,input  wire          gmiiEr      
  ,input  wire          gmii_tx_clk 
  ,output wire  [7:0]   gmii_txd    
  ,output wire          gmii_tx_en  
  ,output wire          gmii_tx_er  
);

  wire                  mux_pktData_valid_um;
  wire  [133:0]         mux_pktData_um;
  wire  [133:0]         pktData_gmii, pktData_um;
  wire                  pktData_valid_gmii, pktData_valid_um;
  wire  [133:0]         pktData_pe, temp_pktData_pe;
  wire                  pktData_valid_pe;
  wire                  w_to_PE_alf;
  wire  [167:0]         metaIn, metaOut;
  wire                  metaIn_valid, metaOut_valid;
  wire  [15:0]          pkt_length_gmii;
  assign                metaIn_valid    = (pktData_valid_gmii == 1'b1) & 
                                          (pktData_gmii[133:132] == 2'b10);
  assign                metaIn          = {8'h02,     //* inPort in bitmap;
                                            4'b0,(4'd1<<pktData_gmii[129:128]), //* outPort in dec;
                                            8'h01,    //* pe in bitmap;
                                            16'h1100, //* bufferID, don't care;
                                            16'h0080, //* 0080 is for dma, 0 is for dra;
                                            16'h0001, //* don't care;
                                            16'h0100, //* don't care;
                                            pkt_length_gmii,
                                            64'h1234};//* timestamp;

  soc_runtime runtime(
    .clk_125m             (clk_125m                     ),
    .sys_rst_n            (rst_n                    ),

    // //* sgmii input;
    // .SFP_REFCLK_P         (SFP_REFCLK_P                 ),
    // .SFP_REFCLK_N         (SFP_REFCLK_N                 ),
    // .FX_RX_P              (FX_RX_P                      ),
    // .FX_RX_N              (FX_RX_N                      ),
    // .FX_TX_P              (FX_TX_P                      ),
    // .FX_TX_N              (FX_TX_N                      ),

    //* gmii port
    .gmii_rx_clk          (gmii_rx_clk                  ),
    .gmiiRxd              (gmiiRxd                      ),
    .gmiiEn               (gmiiEn                       ),
    .gmiiEr               (gmiiEr                       ),
    .gmii_tx_clk          (gmii_tx_clk                  ),
    .gmii_txd             (gmii_txd                     ),
    .gmii_tx_en           (gmii_tx_en                   ),
    .gmii_tx_er           (gmii_tx_er                   ),

    //* um;
    .pktData_valid_gmii   (pktData_valid_gmii           ),
    .pktData_gmii         (pktData_gmii                 ),
    .pkt_length_gmii      (pkt_length_gmii              ),
    .ready_in             (1'b1                         ),
    .pktData_valid_um     (mux_pktData_valid_um         ),
    .pktData_um           (mux_pktData_um               )
  );

  
  //======================= PE_ARRAY         =====================//
  //wire   [7:0]   can_ad_i,can_ad_o;
  // wire           can_ad_sel;
  // assign can_ad= can_ad_sel? 8'dz : can_ad_o;
  // assign can_ad_i = can_ad;
  PE_ARRAY PE_ARRAY_inst(
    //* clock & resets;
    .i_sys_clk            (clk_125m                     ),
    .i_sys_rst_n          (1'b1                         ),
    .i_pe_clk             (clk_50m                      ),
    .i_rst_n              (rst_n                        ),
    //* pkt from/to CPI
    //* pkt from CPI, TODO,
    .i_pe_conf_mac        (48'h8888_8888_8988           ),
    .i_data_valid         (pktData_valid_gmii           ),
    // .i_data_valid         (1'b0           ),
    .i_data               (pktData_gmii                 ),
    .i_meta_valid         (metaIn_valid                 ),
    .i_meta               (metaIn                       ),
    .o_alf                (w_to_PE_alf                  ),
    //* pkt to CPI, TODO,
    .o_data_valid         (pktData_valid_pe             ),
    .o_data               (temp_pktData_pe              ),
    .o_meta_valid         (metaOut_valid                ),
    .o_meta               (metaOut                      ),
    .i_alf                (1'b0                         ),
    //* uart;
      .i_uart_rx          (uart_rx         				      ),
      .o_uart_tx          (uart_tx         				      ),
      .i_uart_cts         (uart_cts        				      ),
      .o_uart_rts         (uart_rts        				      ),
    
    // //* add CAN module's signal
    // .i_can_ad             (),
    // .o_can_ad             (),
    // .o_can_ad_sel         (),
    // .o_can_cs_n           (),
    // .o_can_ale_as         (),
    // .o_can_wr_n           (),
    // .o_can_rd_n           (),
    // .o_can_mode           (),
    // .i_can_int_n          (),
    
    //* pads;
    .i_start_en_pad       (4'd1                         )
  );
  //==============================================================//

  Pkt_Asyn_Send Pkt_Asyn_Send(
    .i_sys_clk            (clk_125m                     ),
    .i_pe_clk             (clk_50m                      ),
    .i_rst_n              (rst_n                        ),
    //* interface for recv/send pkt;
    .i_data_valid         (pktData_valid_pe             ),
    .i_data               (pktData_pe                   ),
    //* TODO
    .o_data_valid         (pktData_valid_um             ),
    .o_data               (pktData_um                   )
  );

  //* write back outport at pkt[131:128];
  `ifdef SUPPORT_MULTIPULE_PORT
    assign  pktData_pe = (metaOut_valid == 1'b0)? temp_pktData_pe:
                          {temp_pktData_pe[133:132],metaOut[163:160],temp_pktData_pe[127:0]};
  `else
    assign  pktData_pe = temp_pktData_pe;
  `endif

  `ifdef TEST_LOOPBACK
    //* test loopback;
    assign mux_pktData_valid_um = pktData_valid_gmii;
    // assign mux_pktData_um       = pktData_gmii;
    assign mux_pktData_um       = {pktData_gmii[133:8], 8'h77};
  `else
    //* test loopback;
    assign mux_pktData_valid_um = pktData_valid_um;
    assign mux_pktData_um       = pktData_um;
  `endif

endmodule
